/**
 * Created by Mic on 16/2/22.
 */

var Character = require('./character');
var util = require('util');
var logger = require('pomelo-logger').getLogger(__filename);
var DDZRule = require('../poker/rule');
var DDZN3Rule = require('../poker/rule3');
var _ = require('underscore');
var consts = require('../../consts/consts');
var undef = 'undefined';

var rand_time = 5;
var base_time = 1;
var c = 0;
var Robot = function (seatIndex, info, desk) {
    Character.call(this, seatIndex, info);
    c++;
    logger.fatal('看下创建了几个机器人 ' + c);

    this.status = '';
    this.deskClient = desk;

    //*********
    this._remains = [];
    this._remaincnts = [];
    this._tryplays = {};
    this._lastplay = null;
    this._dizhupass = false;
    this._dizhu = null;
    this.dizhu = false;

    this._deep = 0;
    this._updates = 0;

    this.robotTime = null;
};
util.inherits(Robot, Character);
module.exports = Robot;

var handler = Robot.prototype;

handler.ready = function (value) {
    this.readyStatus = 1;
    this.setBeishu(value);
    var self = this;
    this.timing = setTimeout(function () {
        self.deskClient.readyResult(self.seatIndex, value);
    }, 1000);
};

handler.addCards = function (cards) {
    this.cards = cards.concat(this.cards);
};
handler.getCards = function () {
    return this.cards;
};
handler.jiao = function () {
    var self = this;
    var time = base_time + parseInt(Math.random() * rand_time);
    var value = !!(time % 2);
    console.log('叫地主 ' + time + ' ' + value);
    this.timing = setTimeout(function () {
        self.deskClient.jiaoResult(self.seatIndex, value);
    }, 1000 * time);
};
handler.qiang = function () {
    var self = this;
    var time = base_time + parseInt(Math.random() * rand_time);
    var value = !!(time % 2);
    console.log('抢地主 ' + time + ' ' + value);

    this.timing = setTimeout(function () {
        self.deskClient.qiangResult(self.seatIndex, value);
    }, 1000 * time);
};
handler.notifyDizhu = function (dipai) {
    this.dizhu = true;
    this.addCards(dipai);
};

handler.double = function () {
    var self = this;
    var time = base_time + parseInt(Math.random() * rand_time);
    var value = !!(time % 2);

    this.timing = setTimeout(function () {
        self.deskClient.doubleResult(self.seatIndex, value);
    }, 1000 * time);
};

handler.notifyDouble = function (value) {
    this.setDoubleStatus(value);
};

// 超时处理              time out
handler.autoJiao = function () {
};
handler.autoQiang = function () {
};
handler.autoPlay = function (index, ondesk, remainsArr, dizhu, pass, remains) {
};
//加倍状态的  ------------------- setter and getter-----------------
handler.setDoubleStatus = function (value) {
    this.doubleStatus = value;
    this.setBeishu(!!value ? 2 : 1);
};
handler.getDoubleStatus = function () {
    return this.doubleStatus;
};

handler.getPlayRound = function () {
    return this.playRound;
};
handler.setPlayRound = function () {
    this.playRound++;
};
handler.setBeishu = function (value) {
    this.beishu *= value;
};
handler.getBeishu = function () {
    return this.beishu;
};
//设置money
handler.setMoney = function (money) {
    this.money += money;
};
handler.getMoney = function () {
    return this.money;
};
//设置不能抢地主 因为不叫了
handler.setCantQiang = function (value) {
    this.pointStatus = value;
};
//返回是否能抢地主 return true = 不能 false = 能
handler.getCantQiang = function () {
    return this.pointStatus;
};
//牌的处理
handler.addCards = function (card) {
    var cards = this.cards.slice(0);
    this.cards = [];
    this.cards = _.union(cards, card);
    return this.cards;
};
handler.takeAwayCards = function (card) {
    if (card == null || card.length == 0)
        return this.cards;
    this.setPlayRound();
    var cards = this.cards.slice(0);
    this.cards = [];
    this.cards = _.difference(cards, card);
    return this.cards;
};
//判断输赢
handler.getWinStatus = function (winIndex) {
    var winStatus = false;
    if (this.dizhu && (winIndex == consts.Desk.Code.Dizhu_win)) {
        winStatus = true;
    } else if (!this.dizhu && (winIndex == consts.Desk.Code.Farmer_win)) {
        winStatus = true;
    }
    return winStatus;
};

handler.getGameCoins = function (winIndex, dizhuIndex, deskBeishu, playerBeishu, baseBet) {
    var winStatus = this.getWinStatus(winIndex);
    var gameCoinArr = [];
    var gameCoin = 0;
    _.each(playerBeishu, function (p) {
        gameCoinArr.push(baseBet * deskBeishu * p);
    });

    if (this.dizhu) {
        gameCoinArr.splice(dizhuIndex, 1);
        gameCoin = (winStatus ? 1 : -1) * (gameCoinArr[0] + gameCoinArr[1])
    } else {
        gameCoin = (winStatus ? 1 : -1) * gameCoinArr[this.seatIndex];
    }
    logger.fatal('game over! ' + this.seatIndex + "  输赢? " + winStatus + gameCoin);

    //判断赢的话赢的钱是否超过自身的钱
    var overtake = false;
    if (gameCoin > this.money) {
        overtake = true;
        gameCoin = this.money;
    }

    //在这里判断下金币是否够的
    if (gameCoin < 0 && (this.getMoney() + gameCoin) < 0) {
        //说明金币不够,只能扣除所有的
        gameCoin = -this.money;
        return {enough: false, gameCoin: gameCoin, beishu: this.getBeishu(), overtake: overtake};
    }
    //quitDesk
    var self = this;
    this.timing = setTimeout(function () {
        self.deskClient.leave(self.baseInfo());
    }, 1000 + Math.random() * 5000);

    //说明金币足够不用管
    return {enough: true, gameCoin: gameCoin, beishu: this.getBeishu(), overtake: overtake};
    //return gameCoin;
    //if (gameCoin < 0 && (this.getMoney() + gameCoin) < 0) {
    //    //说明金币不够,只能扣除所有的
    //    return {enough: false, gameCoin: -this.money, beishu: this.getBeishu()};
    //}
    ////说明金币足够不用管
    //return {enough: true, gameCoin: gameCoin, beishu: this.getBeishu()};
};

//---------------------------robot play------------------------------
handler.onAsk = function (lastCards, remainsCards) {
    var c = this.pickCard(lastCards, remainsCards);
   if (c == null) {
        c = [];
    } else {
        //检查是否牌组里有这些牌
        var cardsCopy = this.cards.slice(0);
        var union = _.intersection(cardsCopy, c);
        if (union.length == 0) {
            //logger.fatal('这个问题很严重' + cardsCopy + ' || ' + c);
            c = [];
            c.push(cardsCopy[cardsCopy.length - 1]);
        }
    }
    var self = this;
    var time = 0;
    if (this.robotTime) {
        time = 0;
    } else {
        time = base_time + Math.random() * rand_time;
    }
    this.timing = setTimeout(function () {
        self.deskClient.playResult(self.seatIndex, c);
    },1000 * time);
};
handler.notifyPlay = function (pos, play, remains, dizhu, pass, remainsCards) {
    //add first pick Card
    if (play == null || play.length == 0) {
        return this.onAsk(play, remainsCards);
    }
    this._dizhu = dizhu;
    this._remains = remainsCards;
    if (null != play) {
        for (var i = 0; i < 3; ++i) {
            if (Array.isArray(remains[i])) {
                this._remaincnts[i] = remains[i].length;
            } else {
                this._remaincnts[i] = remains[i];
            }
        }
        this._tryplays = {};
        this._lastplay = (pos - 1) % 3;
    }

    if (this._dizhu == this._lastplay && (0 == pass.length || pass == null)) {
        this._dizhupass = true;
    } else {
        this._dizhupass = false;
    }
    return this.onAsk(play, remainsCards);
};
//核心部分
handler.pickCard = function (ondesk, remainsCards) {
    if (remainsCards) {
        this._remains = remainsCards;
    }
    if (null != ondesk && DDZN3Rule.isRocket(ondesk)) {
        logger.warn('please no');
        return null;
    }
    var istongmen = null;
    if (this._lastplay == this._dizhu) {
        istongmen = false;
    } else {
        istongmen = true;
    }
    var mengban = istongmen && this.isMengBan();

    if (DDZRule.isBomb(ondesk) && mengban) {
        logger.warn('robot 出炸弹了 上一个是同盟');
        return null;
    }

    //var opremain = this._remaincnts[this._dizhu - 1];
    var opremain = this._remaincnts[this._dizhu];

    var cards = this.cards;
    DDZRule.sort(cards);

    var me = DDZN3Rule.spliteCards(cards, cards.length);
    var he = DDZN3Rule.spliteCards(this._remains, opremain);

    var prepare = this.prepareSearch(me, he);

    console.log('prepare = ' + JSON.stringify(prepare));


    if (null == ondesk || ondesk.length == 0) {
        return this.pickFirstCard(cards, prepare);
    }
    if (this._dizhupass) {
        console.log('上一家为地主  ');
        return null;
    }

    var t = DDZRule.isBomb(ondesk);
    var ret = null;
    if (false != t) {
        ret = this.pickFromItems(ondesk, cards, me.bombs, opremain, DDZRule.pkBomb, prepare, true);
    }

    if (me.rocket.length > 0) {
        cards = this.removeCards(cards, me.rocket[0]);
    }

    for (var i in me.bombs) {
        cards = this.removeCards(cards, me.bombs[i]);
    }

    if (false == t) {
        t = DDZN3Rule.isQuadplex2(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.quadplex2, opremain, DDZN3Rule.pkQuadplex2, prepare, true);
        }
    }

    if (false == t) {
        t = DDZN3Rule.isQuadplex1(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.quadplex1, opremain, DDZN3Rule.pkQuadplex1, prepare, true);
        }
    }

    if (false == t) {
        t = DDZRule.isSequenceTripletPair(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.seqTriPairs, opremain, DDZRule.pkSequenceTripletPair, prepare, false);
        }
    }

    if (false == t) {
        t = DDZN3Rule.isSequenceTripletSingle(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.seqTriSingles, opremain, DDZN3Rule.pkSequenceTripletSingle, prepare, false);
        }
    }

    if (false == t) {
        t = DDZRule.isSequenceTriplet(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.seqTris, opremain, DDZRule.pkSequenceTriplet, prepare, false);
        }
    }

    if (false == t) {
        t = DDZRule.isSequencePair(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.seqPairs, opremain, DDZRule.pkSequencePair, prepare, false);
        }
    }

    if (false == t) {
        t = DDZRule.isSequence(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.sequences, opremain, DDZRule.pkSequence, prepare, false);
        }
    }

    if (false == t) {
        t = DDZRule.isTripletPair(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.tripletPairs, opremain, DDZRule.pkTripletPair, prepare, false);
        }
    }

    if (false == t) {
        t = DDZN3Rule.isTripletSingle(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.tripletSingles, opremain, DDZN3Rule.pkTripletSingle, prepare, false);
        }
    }

    if (false == t) {
        t = DDZRule.isTriplet(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.triplets, opremain, DDZRule.pkTriplet, prepare, false);
        }
    }

    if (false == t) {
        t = DDZRule.isPair(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.pairs, opremain, DDZRule.pkPair, prepare, false, mengban ? 5 : 999);
        }
    }

    if (false == t) {
        t = DDZRule.isSingle(ondesk);

        if (false != t) {
            ret = this.pickFromItems(ondesk, cards, me.singles, opremain, DDZRule.pkSingle, prepare, false, mengban ? 5 : 999);
        }
    }

    if (null == ret && !DDZRule.isBomb(ondesk)) {
        var danger = false;
        if (this.isDiZhu()) {
            danger = this._remaincnts[this._lastplay] < 6;
        } else {
            danger = !mengban && this._remaincnts[this._dizhu] < 7;
        }

        if (me.bombs.length > 0 && danger) {
            return me.bombs[me.bombs.length - 1];
        }
        if (me.rocket.length > 0 && danger) {
            return me.rocket[0];
        }
    }
    return ret;
};
handler.keyof = function (cards) {
    var key = "";

    for (var i in cards) {
        if (cards[i] == 'E2') {
            key += 'F';
        } else if (cards[i] == 'E1') {
            key += 'E';
        } else {
            key += cards[i][1];
        }
    }

    return key;
};
//比较
handler.prepareSearch = function (me, he) {
    var plays = [];
    var pscores = [];
    var scores = {};

    for (var i in me.singles) {
        var s = this.scorePlay(me.singles[i], he.singles, DDZRule.pkSingle);
        scores[this.keyof(me.singles[i])] = s;
        plays.push(me.singles[i]);
        pscores.push(s);
    }

    for (var i in me.pairs) {
        var s = this.scorePlay(me.pairs[i], he.pairs, DDZRule.pkPair);
        scores[this.keyof(me.pairs[i])] = s;
        plays.push(me.pairs[i]);
        pscores.push(s);
    }

    for (var i in me.triplets) {
        var s = this.scorePlay(me.triplets[i], he.triplets, DDZRule.pkTriplet);
        scores[this.keyof(me.triplets[i])] = s;
        plays.push(me.triplets[i]);
        pscores.push(s);
    }

    for (var i in me.seqTris) {
        var s = this.scorePlay(me.seqTris[i], he.seqTris, DDZRule.pkSequenceTriplet) * 2. / (me.seqTris[i].length / 3.);
        scores[this.keyof(me.seqTris[i])] = s;
        plays.push(me.seqTris[i]);
        pscores.push(s);
    }

    for (var i in me.seqPairs) {
        var s = this.scorePlay(me.seqPairs[i], he.seqPairs, DDZRule.pkSequencePair) * 3. / (me.seqPairs[i].length / 2.);
        scores[this.keyof(me.seqPairs[i])] = s;
        plays.push(me.seqPairs[i]);
        pscores.push(s);
    }

    for (var i in me.sequences) {
        var s = this.scorePlay(me.sequences[i], he.sequences, DDZRule.pkSequence) * 5. / me.sequences[i].length;
        scores[this.keyof(me.sequences[i])] = s;
        plays.push(me.sequences[i]);
        pscores.push(s);
    }

    for (var i in me.seqTriPairs) {
        var s = this.scoreCombinePlay(me.seqTriPairs[i], me.seqTris, scores) * 2. / (me.seqTriPairs[i].length / 5.);
        scores[this.keyof(me.seqTriPairs[i])] = s;
        plays.push(me.seqTriPairs[i]);
        pscores.push(s);
    }

    for (var i in me.seqTriSingles) {
        var s = this.scoreCombinePlay(me.seqTriSingles[i], me.seqTris, scores) * 2. / (me.seqTriSingles[i].length / 4.);
        scores[this.keyof(me.seqTriSingles[i])] = s;
        plays.push(me.seqTriSingles[i]);
        pscores.push(s);
    }

    for (var i in me.tripletPairs) {
        var s = this.scoreCombinePlay(me.tripletPairs[i], me.triplets, scores);
        scores[this.keyof(me.tripletPairs[i])] = s;
        plays.push(me.tripletPairs[i]);
        pscores.push(s);
    }

    for (var i in me.tripletSingles) {
        var s = this.scoreCombinePlay(me.tripletSingles[i], me.triplets, scores);
        scores[this.keyof(me.tripletSingles[i])] = s;
        plays.push(me.tripletSingles[i]);
        pscores.push(s);
    }

    //console.log(scores);
    //console.log(plays);

    return {
        "scores": scores,
        "plays": plays,
        "pscores": pscores,
        "me": me
    };
};
handler.pickFirstCard = function (cards, prepare) {
    // console.log('pickFirstCard',cards,prepare);
    //console.log('-----pick first card -----');
    //console.log(cards);
    //console.log(prepare);
    //console.log('----------over---------');
    //
    //console.log('-----pick first card -----');
    //console.log(cards);
    //console.log(JSON.stringify(prepare));
    //console.log('----------over---------');

    var plays = prepare['plays'];
    var pscores = prepare['pscores'];
    var scores = prepare['scores'];
    var me = prepare['me'];

    if (me.quadplex1.length == 1 && cards.length == 6) {
        return me.quadplex1[0];
    }

    if (me.quadplex2.length == 1 && cards.length == 8) {
        return me.quadplex2[0];
    }

    if (me.rocket.length > 0) {
        cards = this.removeCards(cards, me.rocket[0]);
    }

    for (var i in me.bombs) {
        cards = this.removeCards(cards, me.bombs[i]);
    }

    if (cards.length == 0) {
        if (me.bombs.length > 0)
            return me.bombs[me.bombs.length - 1];
        else if (me.rocket.length > 0)
            return me.rocket[0];

        return null;
    }

    if (!this.isDiZhu() && !this.isMengBan() && null != this._remaincnts) {
        // if (this._remaincnts[(this._seat._pos + 1) % 3] == 1) {
        if (this._remaincnts[(this.seatIndex + 1) % 3] == 1) {
            var card = me.singles[me.singles.length - 1];
            if (scores[this.keyof(card)] > 4)
                return card;
        }
    }

    var bestplay = this.tryBestPlay(cards, plays, pscores, 999999);
    return bestplay.play;
};
handler.pickFromItems = function (ondesk, cards, items, opremain, pkfunc, prepare, needbreak, mengban) {
    var bestret = null;
    var bestscore = 999999;
    var plays = prepare['plays'];
    var pscores = prepare['pscores'];

    for (var i = items.length - 1; i >= 0; i--) {
        if (pkfunc(ondesk, items[i]) > 0) {

            if (needbreak) {
                bestret = items[i];
                break;
            } else {
                var c = this.removeCards(cards, items[i]);

                if (null == c) continue;
                var score = prepare['scores'][this.keyof(items[i])];

                if (items[i][0] == 'CA' && items[i][1] == 'BA')
                    console.log("break");

                var bestplay = this.tryBestPlay(c, plays, pscores, 999999);
                var s = bestplay.score + bestplay.remain;

                if (s < bestscore && (typeof mengban === undef || score < mengban)) {
                    bestret = items[i];
                    bestscore = s;
                }
            }
        }
    }

    return bestret;
};
handler.containsCard = function (card, play) {
    var rank = DDZRule.rank(card);
    for (var i in play) {
        var r = DDZRule.rank(play[i]);
        if (rank == r) return true;
    }

    return false;
};
handler.scorePlay = function (play, remains, cpfunc) {
    var score = 0;
    for (var i in remains) {
        var ret = cpfunc(play, remains[i]);
        if (ret > 0) {
            score++;
        } else if (ret == -2) {
            score += 0.2;
        }
    }
    return score;
};
handler.scoreCombinePlay = function (play, combineref, scores) {
    var a = DDZRule.rank(play[0]);

    for (var j in combineref) {
        var b = DDZRule.rank(combineref[j][0]);

        if (a == b) {
            return scores[this.keyof(combineref[j])];
        }
    }

    return 0;
};
handler.tryBestPlay = function (cards, plays, scores, max) {
    var best = {
        "play": null,
        "score": 0,
        "remain": 0,
        "next": null
    };

    if (cards.length == 0) return best;

    var key = this.keyof(cards);

    if (typeof this._tryplays[key] !== undef) {
        return this._tryplays[key];
    }

    this._deep = this._deep + 1;
    best.remain = 999999;

    for (var i in plays) {
        if (!this.containsCard(cards[cards.length - 1], plays[i])) continue;

        var s = scores[i];

        if (s < max) {
            var c = this.removeCards(cards, plays[i]);

            if (null == c) continue;

            if (c.length > 0) {
                var ret = this.tryBestPlay(c, plays, scores, best['remain']);

                if ((ret['remain'] + ret['score']) < best['remain'] &&
                    (ret['remain'] + ret['score'] + s) < max) {
                    best['play'] = plays[i];
                    best['score'] = s;
                    best['remain'] = ret['remain'] + ret['score'];
                    best['next'] = ret;

                    this._updates++;
                }

            } else {
                best['play'] = plays[i];
                best['score'] = s;
                best['remain'] = 0;
                best['next'] = 0;
            }
            //this.logit(cards, best, plays[i]);
        }
    }

    if (null != best.play)
        this._tryplays[key] = best;

    //console.log(cards+" "+best["play"]+" "+best['score']+" "+best['remain']);

    return best;
};

handler.removeCards = function (cards, play) {
    if (play.length > cards.length) return null;

    var p = play.slice(0);
    var c = [];
    for (var i = 0; i < cards.length; ++i) {
        var ignore = false;
        ;
        for (var j = p.length - 1; j >= 0; --j) {
            if (DDZRule.rank(cards[i]) == DDZRule.rank(p[j])) {
                ignore = true;
                p.splice(j, 1);
                break;
            }
        }
        if (!ignore)
            c.push(cards[i]);
    }

    if (p.length == 0) {
        return c;
    }
    return null;
};
handler.isDiZhu = function () {
    return this.dizhu;
};
handler.isMengBan = function () {
    return true;
};

handler.setDouble = function (value) {
    this.isDouble = value;
};
handler.getDouble = function () {
    return this.isDouble;
};

Robot.getCardType = function (cards) {
    var type = 'single';
    var maxv = DDZRule.isSingle(cards);

    if (maxv === false) {
        type = "rocket";
        maxv = DDZN3Rule.isRocket(cards);
        if (maxv) {
            maxv = 'E2';
        }
    }

    if (maxv === false) {
        type = "pair";
        maxv = DDZRule.isPair(cards);
    }

    if (maxv === false) {
        type = "triplet";
        maxv = DDZRule.isTriplet(cards);
    }

    if (maxv === false) {
        type = "bomb";
        maxv = DDZRule.isBomb(cards);
    }

    if (maxv === false) {
        type = "tripletSingle";
        maxv = DDZN3Rule.isTripletSingle(cards);
    }

    if (maxv === false) {
        type = "tripletPair";
        maxv = DDZRule.isTripletPair(cards);
    }

    if (maxv === false) {
        type = "sequence";
        maxv = DDZRule.isSequence(cards);
    }

    if (maxv === false) {
        type = "sequencePair";
        maxv = DDZRule.isSequencePair(cards);
    }

    if (maxv === false) {
        type = "sequenceTriplet";
        maxv = DDZRule.isSequenceTriplet(cards);
    }

    if (maxv === false) {
        type = "quadplex1";
        maxv = DDZN3Rule.isQuadplex1(cards);
    }

    if (maxv === false) {
        type = "quadplex2";
        maxv = DDZN3Rule.isQuadplex2(cards);
    }

    if (maxv === false) {
        type = "sequenceTripletSingle";
        maxv = DDZN3Rule.isSequenceTripletSingle(cards);
    }

    if (maxv === false) {
        type = "sequenceTripletPair";
        maxv = DDZRule.isSequenceTripletPair(cards);
    }

    if (!maxv) type = '';
    return {
        'type': type,
        'maxv': maxv
    };
};


CATCH = function (e) {
    if (typeof e === 'string') console.log(e);
};

RET = function (error, value) {
    if (typeof error === 'string') {
        return error;
    }
    return value;
};
